<template>
  <div class="w-full h-full flex flex-col">
    <div class="flex-1 flex justify-center items-center">
      <div class="relative bg-[#EFF0F6] w-[60%] h-[64%]">
        <img
          src="../../../assets/imgs/correctBorder.webp"
          class="absolute inset-0 z-10 pointer-events-none w-full h-full"
        />
        <div class="absolute inset-0 flex items-center justify-center">
          <div ref="threeRef" class="relative h-[100%] w-[100%]"></div>
        </div>
      </div>
    </div>

    <!-- 控制区域 -->
    <div class="h-56 p-4">
      <Ruler v-model="activeValue" :min="-45" :max="45" />
      <div class="flex justify-center space-x-16 mt-2">
        <div
          class="flex flex-col items-center gap-1 cursor-pointer"
          @click="activeControl = 'rotateZ'"
        >
          <div
            class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mb-1"
            :class="{ '!bg-blue-500 text-white': activeControl === 'rotateZ' }"
          >
            <span class="icon-[icon-park-outline--rotate]"></span>
          </div>
          <span class="text-xs">旋转</span>
        </div>
        <div
          class="flex flex-col items-center gap-1 cursor-pointer"
          @click="activeControl = 'rotateX'"
        >
          <div
            class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mb-1"
            :class="{ '!bg-blue-500 text-white': activeControl === 'rotateX' }"
          >
            <span class="icon-[material-symbols--height] text-xl"></span>
          </div>
          <span class="text-xs">垂直校正</span>
        </div>
        <div
          class="flex flex-col items-center gap-1 cursor-pointer"
          @click="activeControl = 'rotateY'"
        >
          <div
            class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mb-1"
            :class="{ '!bg-blue-500 text-white': activeControl === 'rotateY' }"
          >
            <span class="icon-[material-symbols--width] text-xl"></span>
          </div>
          <span class="text-xs">水平校正</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import Ruler from './components/Ruler.vue'
import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import * as THREE from 'three'

const props = defineProps({
  camera: { type: Object, default: () => ({}) }
})

// 角度
const rotateX = ref(0)
const rotateY = ref(0)
const rotateZ = ref(0)
const activeControl = ref<'rotateX' | 'rotateY' | 'rotateZ'>('rotateZ')
const activeValue = computed({
  get() {
    return activeControl.value === 'rotateX'
      ? rotateX.value
      : activeControl.value === 'rotateY'
        ? rotateY.value
        : rotateZ.value
  },
  set(v: number) {
    if (activeControl.value === 'rotateX') rotateX.value = v
    else if (activeControl.value === 'rotateY') rotateY.value = v
    else rotateZ.value = v
  }
})

// Three.js
const threeRef = ref<HTMLDivElement | null>(null)
let renderer: THREE.WebGLRenderer | null = null
let scene: THREE.Scene | null = null
let camera3D: THREE.PerspectiveCamera | null = null
let plane: THREE.Mesh<THREE.PlaneGeometry, THREE.MeshBasicMaterial> | null = null
let texture: THREE.Texture | null = null
let resizeObs: ResizeObserver | null = null

const PERSPECTIVE_PX = 200 // 与 CSS 的 perspective 对齐

function fovFromPerspectivePx(viewportH: number, p: number) {
  return THREE.MathUtils.radToDeg(2 * Math.atan(viewportH / 2 / p))
}

function fitContainSize(containerW: number, containerH: number, imgW: number, imgH: number) {
  // 模拟 object-contain + 高度优先 60%
  let targetH = containerH * 0.6
  let targetW = targetH * (imgW / imgH)
  if (targetW > containerW) {
    targetW = containerW
    targetH = targetW * (imgH / imgW)
  }
  return { w: targetW, h: targetH }
}

async function initThree() {
  await nextTick()
  const mount = threeRef.value
  if (!mount) return

  const w = mount.clientWidth
  const h = mount.clientHeight

  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, preserveDrawingBuffer: true })
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  renderer.setSize(w, h, true) // 同步 CSS 尺寸以匹配父容器
  mount.appendChild(renderer.domElement)
  // 确保画布视觉尺寸与父容器一致
  renderer.domElement.style.width = '100%'
  renderer.domElement.style.height = '100%'
  renderer.domElement.style.display = 'block'

  // 确保 threeRef 里只有这一个 canvas
  mount.replaceChildren(renderer.domElement)

  scene = new THREE.Scene()
  camera3D = new THREE.PerspectiveCamera(fovFromPerspectivePx(h, PERSPECTIVE_PX), w / h, 0.1, 10000)
  camera3D.position.z = PERSPECTIVE_PX
  scene.add(camera3D)

  // 载入纹理
  const imgSrc = (props.camera?.pic as string) || ''
  const loader = new THREE.TextureLoader()
  texture = await new Promise<THREE.Texture>((resolve, reject) => {
    loader.load(imgSrc, resolve, undefined, reject)
  })
  texture.colorSpace = THREE.SRGBColorSpace

  // 平面尺寸按容器与图片比例适配
  const imgW = texture.image.width
  const imgH = texture.image.height
  const { w: pw, h: ph } = fitContainSize(w, h, imgW, imgH)

  plane = new THREE.Mesh(
    new THREE.PlaneGeometry(pw, ph),
    new THREE.MeshBasicMaterial({ map: texture, transparent: true, side: THREE.DoubleSide })
  )
  scene.add(plane)

  applyRotation()
  renderOnce()

  // 自适应
  resizeObs = new ResizeObserver(() => handleResize())
  resizeObs.observe(mount)
}

function applyRotation() {
  if (!plane) return
  plane.rotation.x = THREE.MathUtils.degToRad(-rotateX.value)
  plane.rotation.y = THREE.MathUtils.degToRad(-rotateY.value)
  plane.rotation.z = THREE.MathUtils.degToRad(rotateZ.value)
}

function handleResize() {
  if (!renderer || !camera3D || !plane || !threeRef.value || !texture) return
  const w = threeRef.value.clientWidth
  const h = threeRef.value.clientHeight

  renderer.setSize(w, h, true)
  camera3D.aspect = w / h
  camera3D.fov = fovFromPerspectivePx(h, PERSPECTIVE_PX)
  camera3D.updateProjectionMatrix()

  // 几何仍按容器 contain
  const imgW = texture.image.width
  const imgH = texture.image.height
  const { w: pw, h: ph } = fitContainSize(w, h, imgW, imgH)
  plane.geometry.dispose()
  plane.geometry = new THREE.PlaneGeometry(pw, ph)

  renderOnce()
}

function renderOnce() {
  if (!renderer || !scene || !camera3D) return
  renderer.render(scene, camera3D)
}

// 响应控制
let rafId: number | null = null
watch([rotateX, rotateY, rotateZ], () => {
  if (rafId) cancelAnimationFrame(rafId)
  rafId = requestAnimationFrame(() => {
    applyRotation()
    renderOnce()
  })
})
watch(
  () => props.camera,
  async () => {
    // 简单处理：重建 three（也可只换纹理）
    disposeThree()
    await initThree()
  },
  { deep: true }
)

onMounted(initThree)
onBeforeUnmount(disposeThree)
function disposeThree() {
  resizeObs?.disconnect()
  resizeObs = null

  if (renderer?.domElement && renderer.domElement.parentNode) {
    renderer.domElement.parentNode.removeChild(renderer.domElement)
  }

  if (plane) {
    plane.geometry.dispose()
    plane.material.dispose()
    plane = null
  }
  texture?.dispose()
  texture = null
  renderer?.dispose()
  renderer = null
  scene = null
  camera3D = null
}

// 导出：使用同视口，提升像素比，所见即所得且不截断
function getCorrectedImage(scale = 2): string | null {
  if (!renderer || !scene || !camera3D || !threeRef.value) return null
  const { clientWidth: w, clientHeight: h } = threeRef.value

  // 备份
  const prevPR = renderer.getPixelRatio()
  const prevSize = renderer.getSize(new THREE.Vector2())

  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2) * scale)
  renderer.setSize(w, h, true)
  renderer.render(scene, camera3D)

  const dataUrl = renderer.domElement.toDataURL('image/png')

  // 还原
  renderer.setPixelRatio(prevPR)
  renderer.setSize(prevSize.x, prevSize.y, true)
  renderOnce()
  return dataUrl
}




defineExpose({ getCorrectedImage })
</script>

<style scoped></style>
